package com.swak.reactivex.context;

import lombok.Data;
import lombok.experimental.Accessors;

/**
 * 引用计数
 * 
 * @author 618lf
 *
 * @param <T>
 */
public class ReferenceThreadContext<T> {

	private final ThreadLocal<Reference<T>> resources = new ThreadLocal<>();

	public T get() {
		return _get();
	}

	public void bind(T context) {
		_put(context);
	}

	public void remove() {
		_remove();
	}

	T _get() {
		Reference<T> stack = resources.get();
		if (stack != null) {
			return stack.getT();
		}
		return null;
	}

	/**
	 * 添加属性
	 * 
	 * @param key
	 * @param value
	 */
	void _put(T context) {
		Reference<T> stack = resources.get();
		if (stack == null) {
			stack = new Reference<>();
			stack.setT(context);
			resources.set(stack);
		}
		stack.addRef();
	}

	/**
	 * 添加属性
	 * 
	 * @param key
	 * @param value
	 */
	void _remove() {
		Reference<T> stack = resources.get();
		if (stack != null) {
			Integer refCount = stack.releaseRef().getRefCount();
			if (refCount == 0) {
				resources.remove();
			}
		}
	}

	@Data
	@Accessors(chain = true)
	private static class Reference<T> {
		private T t;
		private Integer refCount = 0;

		Reference<T> addRef() {
			refCount++;
			return this;
		}

		Reference<T> releaseRef() {
			refCount--;
			return this;
		}
	}
}
